package com.xbongbong.pro.statistic.service.result;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.StarEnum;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.statistic.constant.ChartI18Constant;
import com.xbongbong.pro.statistic.enums.IndicatorRuleEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeEnum;
import com.xbongbong.pro.statistic.enums.ValueTypeEnum;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultInfoDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultPieInfoDTO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataSeriesChartVO;
import com.xbongbong.pro.statistic.through.pojo.dto.ThroughDTO;
import com.xbongbong.saas.constant.workorder.WorkOrderConstant;
import com.xbongbong.saas.domain.entity.WorkOrderStageEntity;
import com.xbongbong.saas.domain.entity.WorkOrderTemplateEntity;
import com.xbongbong.saas.domain.entity.ext.WorkOrderNodeAvgTimeEntityExt;
import com.xbongbong.saas.enums.WorkOrderForStatisticsEnum;
import com.xbongbong.saas.enums.WorkOrderStatusEnum;
import com.xbongbong.saas.enums.business.WorkOrderEnum;
import com.xbongbong.saas.model.WorkOrderEvaluateModel;
import com.xbongbong.saas.model.WorkOrderFlowNodeModel;
import com.xbongbong.saas.model.WorkOrderStageModel;
import com.xbongbong.saas.model.WorkOrderTemplateModel;
import com.xbongbong.saas.service.toolbox.help.ScriptHelp;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.script.Script;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

/**
 * 工单相关统计
 *
 * @author 徐俊杰
 * @version v1.0
 * @date 2019/3/18 14:00
 * @since v1.0
 */
@Service
public class WorkOrderResult extends ChartResultParentService implements ChartResultSystem {
    @Resource
    private WorkOrderTemplateModel workOrderTemplateModel;
    @Resource
    private WorkOrderFlowNodeModel workOrderFlowNodeModel;
    @Resource
    private WorkOrderStageModel workOrderStageModel;
    @Resource
    private WorkOrderEvaluateModel workOrderEvaluateModel;

    @Override
    public Object getTarget(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            case WORK_ORDER_TOTAL_CHART:
                return workOrderTotalChart(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_ADD_HOME:
            case WORK_ORDER_ADD_CHART:
                return workOrderAddHome(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_FINISH_DELAY_HOME:
                return workOrderFinishDelayHome(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_FINISH_HOME:
                return workOrderFinishHome(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_CLOSE_HOME:
                return workOrderCloseHome(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_CLOSE_CHART:
                return workOrderCloseChart(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_FINISH_CHART:
                return workOrderFinishChart(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_FINISH_DELAY_CHART:
                return workOrderFinishDelayChart(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_FINISH_INTIME_CHART:
                return workOrderFinishIntimeChart(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_DEGREE_CHART:
                return workOrderDegreeChart(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_FINISH_TIME_CHART:
                return workOrderFinishTimeChart(chartResultPojo, chartResultDetailVO);
            case WORK_ORDER_PRICE_CHART:
                return workOrderPriceChart(chartResultPojo, chartResultDetailVO);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object getValueTarget(ChartResultPojo chartResultPojo) throws XbbException {
        return null;
    }


    /**
     * 新增工单数
     *
     * @param chartResultPojo     内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/3/19 15:45
     * @since v1.0
     */
    private Object workOrderAddHome(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderAdd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = SystemCodeEnum.WORK_ORDER_ADD_HOME.getName();
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle =  SystemCodeEnum.WORK_ORDER_ADD_HOME.getName();
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 关闭工单数（首页）
     *
     * @param chartResultPojo     内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/3/19 16:09
     * @since v1.0
     */
    private Object workOrderCloseHome(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderClose2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 0;
        String legend = null;
        String unit = null;
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 已完成工单数（首页）
     *
     * @param chartResultPojo     内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/3/19 16:18
     * @since v1.0
     */
    private Object workOrderFinishHome(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderFinish2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 0;
        String legend = null;
        String unit = null;
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 延期完成工单数（首页）
     *
     * @param chartResultPojo     内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/4/15 11:20
     * @since v1.0
     */
    private Object workOrderFinishDelayHome(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderFinishDelay2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE, true);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 0;
        String legend = null;
        String unit = null;
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 关闭工单数（图表中心）
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/4/15 15:53
     * @since v1.0
     */
    private Object workOrderCloseChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderClose2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = I18nMessageUtil.getMessage(I18nStringConstant.CLOSE_WORK_ORDER_NUM);
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle = I18nMessageUtil.getMessage(I18nStringConstant.CLOSE_WORK_ORDER_NUM);
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 已完成工单数（图表中心）
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/4/15 15:55
     * @since v1.0
     */
    private Object workOrderFinishChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderFinish2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = I18nMessageUtil.getMessage(I18nStringConstant.COMPLETED_WORK_ORDER_NUMBER);
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle = I18nMessageUtil.getMessage(I18nStringConstant.COMPLETED_WORK_ORDER_NUMBER);
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 延期完成工单数（图表中心）
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/4/15 15:59
     * @since v1.0
     */
    private Object workOrderFinishDelayChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderFinishDelay2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, true);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = I18nMessageUtil.getMessage(I18nStringConstant.DELAYED_COMPLETED_WORK_ORDER);
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle = I18nMessageUtil.getMessage(I18nStringConstant.DELAYED_COMPLETED_WORK_ORDER);
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 工单总数（图表中心）
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/4/15 16:21
     * @since v1.0
     */
    private Object workOrderTotalChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderTotal2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = IndicatorRuleEnum.WORK_ORDER_TOTAL.getName();
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle = IndicatorRuleEnum.WORK_ORDER_TOTAL.getName();
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 如期完成工单数（图表中心）
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/4/16 10:18
     * @since v1.0
     */
    private Object workOrderFinishIntimeChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = workOrderFinishDelay2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, false);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = I18nMessageUtil.getMessage(I18nStringConstant.SCHEDULE_COMPLETED_WORK_ORDER);
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle = I18nMessageUtil.getMessage(I18nStringConstant.SCHEDULE_COMPLETED_WORK_ORDER);
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 完成工单平均耗时分析
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException 查询工单抛出的异常
     * @author 徐俊杰
     * @date 2019/4/19 9:27
     * @since v1.0
     */
    private Object workOrderFinishTimeChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        String corpid = chartResultPojo.getCorpid();
        Long templateId = chartResultPojo.getRefId();
        //当未选择模板时返回的数据
        if (templateId == null) {
            List<ResultChartVO> chartVOS = new ArrayList<>();
            chartResultDetailVO.setChart(chartVOS);
            return chartResultDetailVO;
        }
        //工单模板筛选
        WorkOrderTemplateEntity template = workOrderTemplateModel.getBykey(templateId, corpid);
        Integer isFree = (template == null) ? WorkOrderConstant.NOT_FREE_WORK_ORDER : template.getIsFree();
        //各阶段名（要塞入一个“总耗时”的阶段）
        List<String> xAxis = new ArrayList<>();
        //默认置入一个“总耗时”
        xAxis.add(0, I18nMessageUtil.getMessage(CommonConstant.AVERAGE_TOTAL_TIME));
        //实际耗时(按时)，要判断各个阶段是否超时，因此要用数组存放--存放未超时的
        JSONArray data4Actual = new JSONArray();
        //预计耗时
        JSONArray data4Expected = new JSONArray();
        //实际耗时(超时)
        JSONArray data4ActualOver = new JSONArray();
        //表格、导出用：预计耗时、实际耗时list
        List<Double> expectedList = new ArrayList<>();
        List<Double> actualList = new ArrayList<>();
        if (Objects.equals(chartResultPojo.getRefId(), 1L)) {
            return systemChartHelp.packageResult4StackedBar(chartResultPojo, chartResultDetailVO,
                    data4Actual, data4Expected, data4ActualOver, expectedList, actualList, xAxis);
        }
        //工单耗时结果处理
        if (WorkOrderConstant.FREE_WORK_ORDER.equals(isFree)) {
            JSONObject freeResult = formHelp.expectedAndActualTimeAvg(chartResultPojo);
            double totalAvgExpectedTime = freeResult.getDoubleValue("averageOne");
            double totalAvgActualTime = freeResult.getDoubleValue("averageTwo");
            dealWithTime("total", data4Actual, data4Expected, data4ActualOver, expectedList, actualList,
                    totalAvgExpectedTime, totalAvgActualTime);
            return systemChartHelp.packageResult4StackedBar(chartResultPojo, chartResultDetailVO,
                    data4Actual, data4Expected, data4ActualOver, expectedList, actualList, xAxis);
        } else {
            //查找workOrderStage
            List<WorkOrderStageEntity> stageList = workOrderStageModel.workOrderStageListByTemplateId(corpid, templateId);
            if (stageList.size() == 0) {
                return systemChartHelp.packageResult4StackedBar(chartResultPojo, chartResultDetailVO,
                        data4Actual, data4Expected, data4ActualOver, expectedList, actualList, xAxis);
            }
            //阶段ids
            Set<Long> stageIdSet = new HashSet<>();
            for (WorkOrderStageEntity entity : stageList) {
                Long stageId = entity.getId();
                if (null == stageId) {
                    continue;
                }
                stageIdSet.add(stageId);
                String stageName = entity.getName();
                if (StringUtil.isEmpty(stageName)) {
                    continue;
                }
                xAxis.add(stageName);
            }
            //查找workOrder
            Set<Long> workOrderIdSet = formHelp.workOrderIdSet(chartResultPojo, "endTime", WorkOrderStatusEnum.FINISH.getCode());
            //查找workOrderFlowNode
            Map<String, Object> nodeMap = new HashMap<>(4);
            nodeMap.put("corpid", corpid);
            nodeMap.put("workOrderIdIn", workOrderIdSet);
            nodeMap.put("stageIdIn", stageIdSet);
            nodeMap.put("del", DelEnum.NORMAL.getDel());
            List<WorkOrderNodeAvgTimeEntityExt> avgTimeEntityExtList = workOrderFlowNodeModel.getStageAverageTime(nodeMap);
            //处理结果
            //平均总预计耗时
            double totalAvgExpectedTime = 0D;
            //平均总实际耗时
            double totalAvgActualTime = 0D;
            for (WorkOrderNodeAvgTimeEntityExt entityExt : avgTimeEntityExtList) {
                Double avgExpectedTime = entityExt.getAvgExpectedTime();
                totalAvgExpectedTime += avgExpectedTime;
                Double avgActualTime = entityExt.getAvgActualTime();
                totalAvgActualTime += avgActualTime;
                dealWithTime("normal", data4Actual, data4Expected, data4ActualOver, expectedList, actualList,
                        avgExpectedTime, avgActualTime);
            }
            dealWithTime("total", data4Actual, data4Expected, data4ActualOver, expectedList, actualList,
                    totalAvgExpectedTime, totalAvgActualTime);
            return systemChartHelp.packageResult4StackedBar(chartResultPojo, chartResultDetailVO,
                    data4Actual, data4Expected, data4ActualOver, expectedList, actualList, xAxis);
        }
    }

    /**
     * 工单服务价格分析（图表中心）
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/4/19 13:49
     * @since v1.0
     */
    private Object workOrderPriceChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> legendList = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.WORK_ORDER_SERVICE_PRICE_ANALYSIS_TITLE).split(","));
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.YUAN));
        String unit1 = systemChartHelp.getUnit("%");

        List<String> unitList = Arrays.asList(unit, unit, unit, unit1, unit1);
        StatisticResultDTO statisticResultDTO = getStatisticResultDto4MomYoy(chartResultPojo, legendList, unitList, WorkOrderEnum.SERVICE_PRICE);
        //右侧展示总数
        statisticResultDTO.setTotalFlag(true);
        statisticResultDTO.setValueTitle(I18nMessageUtil.getMessage(ChartI18Constant.TOTAL_PRICE_OF_WORK_ORDER_SERVICE));
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDTO, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }

    /**
     * 客户满意度分析
     *
     * @param chartResultPojo 入参
     * @param chartResultDetailVO 回参
     * @return java.lang.Object
     * @author 徐俊杰
     * @date 2019/4/22 10:39
     * @since v1.0
     */
    private Object workOrderDegreeChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //工单筛选参数
        BoolQueryBuilder workOrderQuery = chartQueryHelp.workOrderQuery4Base(chartResultPojo, WorkOrderEnum.COMPLETE_TIME.getAttr(), WorkOrderStatusEnum.FINISH.getCode(), null);
        String fieldGroup = WorkOrderEnum.getEsAttr4Keyword(WorkOrderEnum.RATE_STAR);
        //获取星级枚举
        List<ItemPoJo> rateStarList = new ArrayList<>();
        for (StarEnum starEnum : StarEnum.values()) {
            //工单星级在es内刷的是double型，聚合出的key为带小数的字符串型的：0.0，1.0，....5.0，因此在塞入的code要强制转为double型的字符串进行匹配
            Double codeDouble = (double) starEnum.getValue();
            ItemPoJo poJo = new ItemPoJo(starEnum.getText(), codeDouble.toString());
            rateStarList.add(poJo);
        }
        //获取结果
        List<ResultDataSeriesChartVO> list = systemChartHelp.getDataDictionaryDataSeries(IndexTypeEnum.IDX_SAAS_WORK_ORDER, workOrderQuery, fieldGroup, rateStarList);
        //包装回参
        String tableName = I18nMessageUtil.getMessage(CommonConstant.STAR);
        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        StatisticResultPieInfoDTO statisticResultPieInfoDto = new StatisticResultPieInfoDTO(tableName, list, throughDto);
        List<StatisticResultPieInfoDTO> pieInfoDtoList = Collections.singletonList(statisticResultPieInfoDto);
        return systemChartHelp.packageResult4Pie(tableName, pieInfoDtoList, chartResultPojo, chartResultDetailVO);
    }

    /**
     * 获取新增工单数的ElasticAggsPojo
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param valueTypeEnum   值的类型
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @author 徐俊杰
     * @date 2019/3/19 15:40
     * @since v1.0
     */
    private ElasticAggsPojo workOrderAdd2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        String fieldTime = "addTime";
        BoolQueryBuilder workOrderQuery = chartQueryHelp.workOrderQuery4Base(chartResultPojo, fieldTime, null, null);
        return systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_WORK_ORDER, workOrderQuery, fieldTime);
    }

    /**
     * 获取关闭工单数的ElasticAggsPojo
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param valueTypeEnum   值的类型
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @author 徐俊杰
     * @date 2019/3/19 16:04
     * @since v1.0
     */
    private ElasticAggsPojo workOrderClose2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        String fieldTime = "closeTime";
        BoolQueryBuilder workOrderQuery = chartQueryHelp.workOrderQuery4Base(chartResultPojo, fieldTime, WorkOrderStatusEnum.CLOSE.getCode(), null);
        return systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_WORK_ORDER, workOrderQuery, fieldTime);
    }

    /**
     * 获取已完成工单数的ElasticAggsPojo
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param valueTypeEnum   值的类型
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @author 徐俊杰
     * @date 2019/3/19 16:17
     * @since v1.0
     */
    private ElasticAggsPojo workOrderFinish2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        String fieldTime = "endTime";
        BoolQueryBuilder workOrderQuery = chartQueryHelp.workOrderQuery4Base(chartResultPojo, fieldTime, WorkOrderStatusEnum.FINISH.getCode(), null);
        return systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_WORK_ORDER, workOrderQuery, fieldTime);
    }

    /**
     * 获取延期或按时完成工单数的ElasticAggsPojo
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param valueTypeEnum   值的类型
     * @param ifDelay 是否延期
     * @return com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo
     * @author 徐俊杰
     * @date 2019/4/15 10:49
     * @since v1.0
     */
    private ElasticAggsPojo workOrderFinishDelay2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum, Boolean ifDelay) throws XbbException {
        String fieldTime = WorkOrderEnum.COMPLETE_TIME.getSaasAttr();
        String actualTime = WorkOrderForStatisticsEnum.ACTUAL_TIME.getSaasAttr();
        String expectedTime = WorkOrderForStatisticsEnum.EXPECTED_TIME.getSaasAttr();
        Script script;
        String extratime = String.valueOf(WorkOrderConstant.EXTRATIME);
        if (ifDelay) {
            //实际耗时 - 预计耗时 > 额外超时时间
            script = ScriptHelp.minusFilter4Gt(actualTime, expectedTime, extratime);
        } else {
            //实际耗时 - 预计耗时 <= 额外超时时间
            script = ScriptHelp.minusFilter4Elt(actualTime, expectedTime, extratime);
        }
        BoolQueryBuilder workOrderQuery = chartQueryHelp.workOrderQuery4Base(chartResultPojo, fieldTime, WorkOrderStatusEnum.FINISH.getCode(), script);
        workOrderQuery.mustNot(termQuery(expectedTime, WorkOrderConstant.EXPECTED_TIME_ZERO));
        return systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_WORK_ORDER, workOrderQuery, fieldTime);
    }

    /**
     * 工单总量分析（图表中心）
     * 获取工单总数的ElasticAggsPojo
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param valueTypeEnum   值的类型
     * @return com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo
     * @author 徐俊杰
     * @date 2019/4/15 16:17
     * @since v1.0
     */
    private ElasticAggsPojo workOrderTotal2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        String fieldTime = "addTime";
        int futureCalc = 1;
        //计算未来时间
        chartResultPojo.setFutureCalc(futureCalc);
        /*--------处理查询条件：先处理时间段内的所有工单数-------*/
        BoolQueryBuilder workOrderQuery = chartQueryHelp.workOrderQuery4Base(chartResultPojo, fieldTime, null, null);
        ElasticAggsPojo timePeriodAggs = systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_WORK_ORDER, workOrderQuery, fieldTime);
        /*--------再获取出截至到startTime的所有工单数--------*/
        //移除addTime，重新塞入新的条件
        esHelper.removeSearchCondition(workOrderQuery, fieldTime);
        int startTime = chartResultPojo.getStartTime();
        workOrderQuery.filter(rangeQuery(fieldTime).lt(startTime));
        Integer pastTotal = systemChartHelp.getCount4Total(IndexTypeEnum.IDX_SAAS_WORK_ORDER, workOrderQuery);
        //处理结果
        return ChartResultUtil.totalAggs(timePeriodAggs, pastTotal, valueTypeEnum, chartResultPojo, futureCalc);
    }

    /**
     * 获取工单相关的ElasticAggsPojo
     * 时间分组+某字段求和
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param valueTypeEnum 值的类型
     * @param attrEnum 求和的字段
     * @return com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo
     * @author 徐俊杰
     * @date 2019/4/19 10:37
     * @since v1.0
     */
    private ElasticAggsPojo workOrderDoubleAgg(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum, WorkOrderEnum attrEnum) throws XbbException {
        String fieldTime = "addTime";
        String sumField = WorkOrderEnum.getEsAttr4Keyword(attrEnum);
        BoolQueryBuilder workOrderQuery = chartQueryHelp.workOrderQuery4Base(chartResultPojo, fieldTime, null, null);
        chartResultPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
        return systemChartHelp.getDouble4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_WORK_ORDER, workOrderQuery, fieldTime, sumField);
    }

    /**
     * 同时获取并封装环比、同比统计结果
     *
     * @param chartResultPojo 参数pojo
     * @param legendList 图的legend
     * @param unitList 各条线的单位，与legendList大小一致
     * @param attrEnum 求和字段
     * @return com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultDTO
     * @author 徐俊杰
     * @date 2019/4/19 13:44
     * @since v1.0
     */
    private StatisticResultDTO getStatisticResultDto4MomYoy(ChartResultPojo chartResultPojo, List<String> legendList, List<String> unitList, WorkOrderEnum attrEnum) throws XbbException {
        ElasticAggsPojo thisMonthAggsPojo = workOrderDoubleAgg(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, attrEnum);
        Integer startTime = chartResultPojo.getStartTime();
        Integer endTime = chartResultPojo.getEndTime();
        //------环比结果
        //先把chartResultPojo拷贝出一份，下面都用chartResultPojoCopy，防止时间的变更（环比、同比需要改变开始结束时间）对原有chartResultPojo内参数的影响
        ChartResultPojo chartResultPojoCopy = new ChartResultPojo();
        BeanUtil.copyProperties(chartResultPojo, chartResultPojoCopy);
        ChartResultUtil.momOrYoyTime(chartResultPojoCopy, true, startTime, endTime);
        ElasticAggsPojo lastMonthAggsPojo = workOrderDoubleAgg(chartResultPojoCopy, ValueTypeEnum.ARRAY_TYPE, attrEnum);
        ChartResultUtil.momOrYoyTime(chartResultPojoCopy, false, startTime, endTime);
        ElasticAggsPojo lastYearAggsPojo = workOrderDoubleAgg(chartResultPojoCopy, ValueTypeEnum.ARRAY_TYPE, attrEnum);
        //------处理环比、同比比例
        ElasticAggsPojo resultMom = systemChartHelp.getMomYoyResult(thisMonthAggsPojo, lastMonthAggsPojo);
        ElasticAggsPojo resultYoy = systemChartHelp.getMomYoyResult(thisMonthAggsPojo, lastYearAggsPojo);

        List<StatisticResultInfoDTO> statisticResultInfoDtoList = systemChartHelp.getInfoDtos4MomYoy(chartResultPojo, legendList, unitList, thisMonthAggsPojo, lastMonthAggsPojo, lastYearAggsPojo, resultMom, resultYoy);
        StatisticResultDTO statisticResultDTO = new StatisticResultDTO(true, thisMonthAggsPojo.getTotal(), null, statisticResultInfoDtoList);
        return statisticResultDTO;
    }

    /**
     * 已完成工单耗时分析堆叠图的一条数据
     *
     * @param which “total”代表总耗时，要塞入第一个位置
     * @param data4Actual 按时
     * @param data4Expected 预计
     * @param data4ActualOver 超时
     * @param expectedList 表格、导出用：预计耗时list
     * @param actualList 表格、导出用：实际耗时list
     * @param avgExpectedTime 平均预计耗时
     * @param avgActualTime 平均实际耗时
     * @author 徐俊杰
     * @date 2019/4/19 9:13
     * @since v1.0
     */
    private void dealWithTime(String which, JSONArray data4Actual, JSONArray data4Expected, JSONArray data4ActualOver,
                              List<Double> expectedList, List<Double> actualList, double avgExpectedTime, double avgActualTime) {
        //超过WorkOrderConstant.EXTRATIME秒，不算超时
        double flag = Arith.div(avgExpectedTime + WorkOrderConstant.EXTRATIME, TimeConstant.SECONDS_PER_HOUR, 2);
        avgExpectedTime = Arith.div(avgExpectedTime, TimeConstant.SECONDS_PER_HOUR, 2);
        avgActualTime = Arith.div(avgActualTime, TimeConstant.SECONDS_PER_HOUR, 2);
        //处理预计耗时
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("value", avgExpectedTime);
        //处理实际耗时（两者只能共存其一：按时or超时）
        JSONObject object = new JSONObject();
        JSONObject objectOver = new JSONObject();
        if (avgActualTime <= flag) {
            //未超时
            object.put("value", avgActualTime);
            //超时的，置为空
            objectOver.put("value", 0);
        } else {
            //未超时，置空
            object.put("value", 0);
            //超时
            objectOver.put("value", avgActualTime);
        }
        String total = "total";
        if ((total).equals(which)) {
            expectedList.add(0, avgExpectedTime);
            actualList.add(0, avgActualTime);
            //平均总耗时的，放到第一个
            data4Actual.add(0, object);
            data4Expected.add(0, jsonObject);
            data4ActualOver.add(0, objectOver);
        } else {
            expectedList.add(avgExpectedTime);
            actualList.add(avgActualTime);
            data4Actual.add(object);
            data4Expected.add(jsonObject);
            data4ActualOver.add(objectOver);
        }
    }
}
